Forms are an excellent way of getting input from visitors to your site. However,
unless you are able to write and upload your own CGI scripts, you are very
limited in what you can do with them. Most ISPs only provide some sort of
form-to-email script, to send the contents of the form to you. JavaScript is
able to work with each element of a form, as well as the complete form, and
there are various event handlers associated with forms. This means you can
process information from forms on the visitor's browser, with no need for CGI
scripts and no network delays while scripts are run. It also means you can do do
things like checking the contents of a form before sending it to the normal form
to mail script.

Here's a basic example:

<form name="SimpleForm" onSubmit="return CheckForm();" method="POST" action="/cgi-bin/formmail.pl">
<input type="hidden" name="recipient" value="javascript@amigaformat.co.uk">
Name: <input type="text" name="realname"><br>
Email: <input type="text" name="email"><br>
<input type="submit"><input type="reset">
</form>

This is a standard form with two input fields, the only difference is the
onSubmit handler. The handler performs the defined action and only submits the
form if it returns true. So you can use this to check the contents of the form
before sending them. If anything is wrong, the form isn't sent. This calls the
following function and returns its result The function is a lot simpler than it
looks. There are two lines that do the real work, the rest has been covered
before.

<script type="text/javascript" language="javascript">
<!--
function CheckForm()
{
if (document.SimpleForm.realname.value.length == 0)
{
alert('You must give a name');
return false;
}
{
alert('You must give a valid email address');
return false;
}
return true;
}
// -->
</script>

The if statement executes statements depending on whether a condition is true.
The syntax is

if (condition) {statements} else {statements}

The else part is optional. If you only have a single statement, the curly braces
aren't needed. The parentheses around the condition are compulsory. This is how
we use it in the script

if (document.SimpleForm.realname.value.length == 0)

In English, this is referring to "the length of the value (contents) of the
realname field of the form called SimpleForm in the current page". The ==
function tests for equality (the = operator is used to assign values).
document.SimpleForm.realname is the form object, this has the property value,
which holds the contents of the input box in this case. This is a string object,
and any string object has the property length. if the length of the input box's
contents is zero, i.e. it's empty, the function puts up an error message to let
the user know what's wrong, and returns false to prevent the form being
submitted.

The second if statement uses a different test, we check that the email box has
what looks like a valid email address.

if (document.SimpleForm.email.value.indexOf('@') == -1 )

The indexOf method returns the position of the first occurrence of the argument,
or -1 if it is not found. If the email field contained me@my.isp.com,
indexOf('@') would return 2 (the first character is at position zero).
indexOf('m') would return 0 since it returns the first match. You can change the
start position with a second argument, indexOf('m',2) would starting search at @
and return 3. The position returned is always counted from the beginning of the
string, no matter where the search starts.

Any valid domain will contain at least one full stop, and this will be after the
@. We can check for this using indexOf's companion, lastIndexOf to return the
position of the last full stop in the address.


if (
(document.SimpleForm.email.value.indexOf('@') < 1 ) ||
(document.SimpleForm.email.value.indexOf('@') >= document.SimpleForm.email.value.lastIndexOf('.'))
)

This is split over several lines for readability, but it would work just as well
written on a single line. We've introduced a new operator, ||, the logical Or.
The following statements will be executed if at least one of the conditions is
true, if there's no @ or there's no full stop after the @. If both conditions
have to be true, use &&, the logical And operator. The first test checks that
the position of the @ character is at least 1. Zero would mean that the address
started with @.




Popping up a warning requester when the form is completed is fine with a short
form like this. If you have a long form and the onSubmit function picks up an
error in an early field, your visitor has to scroll up to find the fault,
correct it and then scroll back down to the bottom to resend, hoping that the
onSubmit function doesn't pick up another error. There is a solution, each form
element can have an event handler attached to it.

<input type="text" name="realname" onChange="CheckName();return true">

The onChange handler is invoked when the contents of the input box are changed.
It doesn't happen for each character typed, that would be a horrendous waste of
CPU time, but when the input is complete. That is, when the user moves the
cursor to a different field or presses Return or Tab. Once this happens, the
browser executes this function

function CheckName()
{
if (document.LongForm.realname.value.length == 0)
{
alert('You must give a name');
return false;
}
return true;
}

You can add a function to check each field, although if you are only checking
whether the field contains data or not, a more general function would be better
than a separate one for each field. Here's a general function to test that a
field contains some data.

function CheckField(Field,ErrorMessage)
{
if (Field.value.length == 0)
{
alert(ErrorMessage);
return false;
}
return true;
}

Did you see that we sneaked in another new feature here? We have given the
function two arguments. The first is the field to check, the second is the error
message to be shown if the field is empty. The definition of the input box is
now

<input type="text" name="realname" onChange="CheckField(this,'You must give a name');return true">

The first argument given is "this", which contains the current object. In the
case of an OnChange handler, this contains the field object. With the onSubmit
handler, this contains the form object.

Our form now checks that each field is valid as the users leaves it, but what if
he skips a field completely, bypassing the onChange handler? We still need an
overall check from onSubmit. This is a lot easier now, since we already have the
functions to check these fields. The onSubmit handler could now calls a function
like

function CheckFullForm(ThisForm)
{
if (CheckField(ThisForm.realname,'You must give a name') == false) return false;
if (CheckField(ThisForm.address,'Please complete the Address field') == false) return false;
// add any other checks here
if (CheckEmail() == false) return false;
return true;
}

We use a separate function to check the email field, because we are doing more
than checking whether it is empty or not. This is the same as the check we used
before, but as a separate function.







**boxout: Form event handlers

We have already seen the onSubmit handler, it's partner is onReset. As you would
expect, this is called when the reset button is clicked, and the form is not
cleared if the function returns false. the most common use of this is

onReset="return confirm('Do you really want to clear the form?')"

This asks the user if they want to clear the form and returns false of they
don't. The confirm() function is similar to alert() except that the requester
has two buttons, OK and Cancel. It returns true if OK is pressed, false for
Cancel. However, onReset doesn't seem to work in anything but Netscape.

The onChange handler applies to text, textarea, fileupload, password and select
objects. In the case of the first four, the handler is invoked when the cursor
leaves the object after changing the contents. For the select object, onChange
is invoked when a new selection is made.

The other form elements; checkbox, button, radio, submit and reset, use the
onClick handler. As the name implies, this is run whenever the user clicks on
the object.





**boxout: Password protecting a page

It's not possible to securely protect a web page without access to CGI scripts
or the server configuration files. JavaScript source is visible to the user, so
proper password checks are difficult. But there is a reasonably secure method
you can use with JavaScript. It's a variation on the "hidden URL" method, where
you give the page an obscure URL and don't link it from anywhere. This makes the
page almost impossible to find without knowing the exact URL but means the user
has to type in a long URL to gain access. This short JavaScript form makes the
process easier

<form name="PasswordForm" onSubmit="location.replace('hiddenfiles/' + this.pword.value + '.html');return false">
<input name="pword" type="text">
</form>

There is no Submit button, because a form containing a single text field is
submitted when Return is pressed in the field. The onSubmit action uses the
location.replace() method. This takes a URL as an argument and loads that URL in
place of the current document. In this case, the URL is based on the password.
The handler is called by the form, so that's what "this" refers to.
this.pword.value is the same as document.PasswordForm.pword.value. The handler
ends with "return false" because we don't want the browser to try to submit the
form anywhere, everything is done by location.replace().


**Home.png: Not only are we checking that the field have been competed, we are
also testing whether the email address is in a valid format.



**LongForm.png: you wouldn't want to spend time completing the whole form, only
to be told there was an error near the start. onChange lets you check the user's
input as he enters it.